Imports System.Data.SqlClient
Imports System.Object
Imports System.Reflection
Imports System.Configuration
Imports System.Globalization
Imports System.Threading

''' -----------------------------------------------------------------------------
''' <summary>
''' The data state of the Business object
''' </summary>
''' <remarks>
''' </remarks>
''' -----------------------------------------------------------------------------
<Serializable()> Public Enum DataState
    IsUnchanged
    IsNew
    IsDirty
    IsDeleted
End Enum
''' -----------------------------------------------------------------------------
''' <summary>
''' Each command type used in a buiness object
''' </summary>
''' <remarks>
''' </remarks>
''' -----------------------------------------------------------------------------
<Serializable()> Public Enum CommandType
    SQLSelect
    SQLInsert
    SQLUpdate
    SQLDelete
End Enum



''' -----------------------------------------------------------------------------
''' Project	 : CObject
''' Class	 : CDataTable
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' An ArrayList holding CObjects.  Can be bound to GUI elements.
''' </summary>
''' <remarks>
''' </remarks>
''' -----------------------------------------------------------------------------
<Serializable()> Public Class CDataTable
    Inherits ArrayList
    Public Function GetObjectByKey(ByVal poKey As Object) As CObject
        Dim loObject As CObject
        For Each loObject In Me
            If Not loObject.Properties(loObject.Key) Is Nothing Then
                If loObject.Properties(loObject.Key).NewValue = poKey Then
                    Return loObject
                    Exit Function
                End If
            End If
        Next
        Return Nothing
    End Function
    Public Sub Save(ByVal poConnection As SqlConnection)
        Dim loTran As CTransaction = New CTransaction
        Dim lintCount As Integer

        For lintCount = 0 To Me.Count - 1
            loTran.AddObject(CType(Me.Item(lintCount), CObject))
        Next
        loTran.Save()
        loTran = Nothing

    End Sub
End Class

''' -----------------------------------------------------------------------------
''' Project	 : CObject
''' Class	 : CData
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' CData is the Object holding the values,  old and new,  of each Property.
''' If you are looking at the CObject base Properties Hashtable,  you will 
''' need to make sure you are pulling the NewValue or OldValue Property.
''' </summary>
''' <remarks>
''' </remarks>
''' -----------------------------------------------------------------------------
<DefaultMember("NewValue"), Serializable()> Public Class CData

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Keeps Old and New Values for Object 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>    
    ''' -----------------------------------------------------------------------------
    Private moNewValue As Object
    Private moOldValue As Object
    Public Property NewValue() As Object
        Get
            If IsDBNull(moNewValue) Then
                Return DBNull.Value
            Else
                Return moNewValue
            End If
        End Get
        Set(ByVal Value As Object)
            moNewValue = Value
        End Set
    End Property
    Public Property OldValue() As Object
        Get
            If IsDBNull(moOldValue) Then
                Return DBNull.Value
            Else
                Return moOldValue
            End If
        End Get
        Set(ByVal Value As Object)
            moOldValue = Value
        End Set
    End Property
End Class


''' -----------------------------------------------------------------------------
''' Project	 : CObject
''' Class	 : CObject
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' The Base object for any busines object.  This is implemented from any business object
''' </summary>
''' <remarks>
''' </remarks>
''' -----------------------------------------------------------------------------
<Serializable()> Public MustInherit Class CObject
 
    Public Const NULL_DATE As Date = #1/1/1900#
    Protected mhtProperties As Hashtable
    Public MustOverride ReadOnly Property Key() As String
    Public MustOverride Function Clone() As CObject
    Public MustOverride ReadOnly Property SourceDataBase() As ConnectionServer.Connection.SourceDataBase
    Private mbIsDeleted As Boolean
    Private mbIsHTML As Boolean = True
    ''' <summary>
    ''' Will fire a given function after the object has been saved using the Save Meathod.  Correct Syntext is...
    ''' delAfterSave = New AfterSaveHandler(AddressOf [Name of function to be fired])
    ''' </summary>
    ''' <param name="poObject"></param>
    ''' <param name="idbTran"></param>
    ''' <param name="idbConn"></param>
    ''' <remarks></remarks>
    Protected Delegate Sub AfterSaveHandler(ByVal poObject As CObject, ByVal idbTran As SqlTransaction, ByVal idbConn As SqlConnection)
    Protected delAfterSave As AfterSaveHandler

    Protected Delegate Sub BeforeSaveHandler(ByVal poObject As CObject, ByVal idbTran As SqlTransaction, ByVal idbConn As SqlConnection)
    Protected delBeforeSave As AfterSaveHandler

    Protected Delegate Sub TransactionOutputHandler(ByVal poObject As Object)
    Protected delTransactionOutPut As TransactionOutputHandler

    Private mbTestMode As Boolean = False

    <System.ComponentModel.Description("Return Exec dbo.ProcName {Field1},{Field2},...")> Protected Friend MustOverride Function ProcedureSigniture(ByVal peCommandType As CommandType) As String
    Public Sub New()
        mhtProperties = New Hashtable

    End Sub
   
    Public ReadOnly Property USCulture() As CultureInfo
        Get
            Return Globalization.CultureInfo.CreateSpecificCulture("en-us")
        End Get
    End Property
    Public Function USDateString(ByVal dtDate As DateTime) As String
        Return dtDate.ToString("d", USCulture)
    End Function
    Public Enum StringFormat
        ShortDate
        LongDate
        LongDateShortTime
        LongDateLongTime
        GeneralDateTime
        Month
        RoundTrip
        Sortable
        Universal
        YearMonth
        LongTime
        ShortTime
    End Enum

    Public Function DateString(ByVal dtDate As DateTime, Optional ByVal f As StringFormat = StringFormat.ShortDate, Optional ByVal pCultureInfo As CultureInfo = Nothing) As String
        Dim lsDate As String = String.Empty
        Dim lCulture As CultureInfo
        If pCultureInfo Is Nothing Then
            lCulture = Thread.CurrentThread.CurrentCulture
        Else
            lCulture = pCultureInfo
        End If


        Select Case f
            Case StringFormat.GeneralDateTime
                lsDate = dtDate.ToString("g", lCulture)
            Case StringFormat.LongDate
                lsDate = dtDate.ToString("D", lCulture)
            Case StringFormat.LongDateLongTime
                lsDate = dtDate.ToString("F", lCulture)
            Case StringFormat.LongDateShortTime
                lsDate = dtDate.ToString("f", lCulture)
            Case StringFormat.Month
                lsDate = dtDate.ToString("m", lCulture)
            Case StringFormat.RoundTrip
                lsDate = dtDate.ToString("r", lCulture)
            Case StringFormat.ShortDate
                lsDate = dtDate.ToString("d", lCulture)
            Case StringFormat.Sortable
                lsDate = dtDate.ToString("s", lCulture)
            Case StringFormat.Universal
                lsDate = dtDate.ToString("U", lCulture)
            Case StringFormat.YearMonth
                lsDate = dtDate.ToString("Y", lCulture)
            Case StringFormat.LongTime
                lsDate = dtDate.ToString("T", lCulture)
            Case StringFormat.ShortTime
                lsDate = dtDate.ToString("t", lCulture)
        End Select
        Return lsDate
    End Function
    Public ReadOnly Property HTTPSchema() As String
        Get
            Dim loAppSettings As AppSettingsReader = New AppSettingsReader
            Return loAppSettings.GetValue("HTTPSchema", GetType(System.String)).ToString
        End Get
    End Property
    Public Sub New(ByVal piKey As Integer)
        Me.New()
        Dim loColl As CCollection = New CCollection(Me.Clone, Me.Key & " = " & piKey.ToString)
        If Not loColl.DataObject Is Nothing Then

            mhtProperties = loColl.DataObject.Properties

        End If
    End Sub
    Public Sub New(ByVal psKey As String)
        Me.New()
        Dim loColl As CCollection = New CCollection(Me.Clone, Me.Key & " = '" & psKey & "'")
        If Not loColl.DataObject Is Nothing Then

            mhtProperties = loColl.DataObject.Properties

        End If
    End Sub
    Public Overridable Sub Refresh()
        Dim loColl As CCollection = New CCollection(Me.Clone, Me.Key & " = " & CType(Properties.Item(Me.Key), CData).NewValue.ToString)
        If Not loColl.DataObject Is Nothing Then
            mhtProperties = New Hashtable
            mhtProperties = loColl.DataObject.Properties
        Else
            mhtProperties = Nothing
        End If
    End Sub
    Public Property IsHTML() As Boolean
        Get
            Return mbIsHTML
        End Get
        Set(ByVal value As Boolean)
            mbIsHTML = value
        End Set
    End Property
    Public Function GetProcedure(ByVal peCommandType As CommandType) As SqlCommand
        Dim loComm As SqlCommand = New SqlCommand

        Dim lsItem As String
        Dim lsProc As String = ProcedureSigniture(peCommandType)

        For Each lsItem In Properties.Keys

            If lsProc.ToLower.IndexOf("{" & lsItem & "}") >= 0 Then


                If Not IsDBNull(Properties(lsItem.ToLower).newvalue) Then

                    Dim p As SqlParameter = loComm.CreateParameter
                    p.ParameterName = "@" & lsItem.Replace(" ", "_").Replace("[", "").Replace("]", "")
                    p.Value = HTMLEnCode(Properties(lsItem.ToLower).newvalue)
                    Select Case Properties(lsItem.ToLower).NewValue.GetType.FullName
                        Case "System.String"
                            p.SqlDbType = SqlDbType.NVarChar
                        Case "System.DateTime"
                            p.SqlDbType = SqlDbType.DateTime
                        Case "System.Boolean"
                            p.SqlDbType = SqlDbType.Bit
                        Case "System.Double"
                            p.SqlDbType = SqlDbType.Decimal
                        Case "System.Integer"
                            p.SqlDbType = SqlDbType.Int
                    End Select
                    loComm.Parameters.Add(p)
                    lsProc = lsProc.ToLower.Replace("{" & lsItem & "}", "@" & lsItem.Replace(" ", "_").Replace("[", "").Replace("]", ""))
                End If

            End If

        Next
    
        Do While (lsProc.IndexOf("{") > -1)
            Dim ix As Integer = lsProc.IndexOf("{")
            Dim iy As Integer = lsProc.IndexOf("}") + 1
            Dim ls As String = lsProc.Substring(ix, iy - ix)

            lsProc = lsProc.Replace(ls, "NULL")


        Loop

        loComm.CommandText = lsProc
        Return loComm

    End Function


    <Obsolete("Stop using this!Use GetProcedure instead.", True)> _
    Public Function GetProcedureText(ByVal peCommandType As CommandType) As String

        Dim lsItem As String
        Dim lsReturn As String = ProcedureSigniture(peCommandType)
        Dim loResponse As Object
        Dim lasARR() As String
        Dim liCount As Integer
        Dim lsSQL As String
        For Each lsItem In Properties.Keys
            If IsDBNull(Properties(lsItem.ToLower).newvalue) Then
                loResponse = "NULL"
            Else
                Select Case Properties(lsItem.ToLower).NewValue.GetType.FullName
                    Case "System.String"
                        'Replace apostrophy's with double apostrophy
                        loResponse = "'" & Replace(Properties(lsItem.ToLower).NewValue.ToString, "'", "''") & "'"
                    Case "System.DateTime"
                        loResponse = "'" & USDateString(Properties(lsItem.ToLower).NewValue) & "'"
                    Case "System.Boolean"
                        loResponse = CInt(Properties(lsItem.ToLower).NewValue)
                    Case Else
                        loResponse = Properties(lsItem.ToLower).NewValue
                End Select
            End If
            lsReturn = lsReturn.Replace("{" & lsItem & "}", loResponse)
        Next
        lasARR = lsReturn.Split("{")
        lsReturn = ""
        For liCount = lasARR.GetLowerBound(0) To lasARR.GetUpperBound(0)
            If InStr(lasARR(liCount), "}") Then
                lsSQL = Mid(lasARR(liCount), InStr(lasARR(liCount), "}") + 1)
                lsSQL = "NULL" & lsSQL
            Else
                lsSQL = lasARR(liCount)
            End If
            lsReturn += lsSQL
        Next

        loResponse = Nothing
        Return lsReturn
    End Function
    Public Sub MarkAsDeleted()
        mbIsDeleted = True
    End Sub
    Public ReadOnly Property MarkedForDeletion() As Boolean
        Get
            Return mbIsDeleted
        End Get
    End Property

    Protected Friend Function GetCommandObj() As SqlCommand
        Select Case State
            Case DataState.IsNew
                Return GetProcedure(CommandType.SQLInsert)
            Case DataState.IsDirty
                Return GetProcedure(CommandType.SQLUpdate)
            Case DataState.IsDeleted
                Return GetProcedure(CommandType.SQLDelete)
            Case Else
                Throw New SystemException("GetCommand has Unknown Datastate")
        End Select

    End Function

 
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' A hashtable holding the properties of the business object
    ''' </summary>
    ''' <returns>A populated hashtable</returns>
    
    ''' -----------------------------------------------------------------------------
    Public Property Properties() As Hashtable
        Get
            Return mhtProperties
        End Get
        Set(ByVal value As Hashtable)
            mhtProperties = value
        End Set
    End Property
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Set's the property for the business object.
    ''' </summary>
    ''' <param name="psProperty">Name of the property.</param>
    ''' <param name="poValue">The value of the property</param>
    ''' <remarks>
    ''' The names passed in for the property must be the names of the fields in the database.
    ''' </remarks>    
    ''' -----------------------------------------------------------------------------
    Protected Friend Sub SetProperty(ByVal psProperty As String, ByVal poValue As Object)

        If Not mhtProperties.ContainsKey(psProperty.ToLower) Then
            mhtProperties.Add(psProperty.ToLower, New CData)
        End If

        mhtProperties(psProperty.ToLower).NewValue = poValue

    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Gets the value in the property
    ''' </summary>
    ''' <param name="psProperty"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>   
    ''' -----------------------------------------------------------------------------
    Protected Friend Function GetProperty(ByVal psProperty As String) As Object
        If mhtProperties.ContainsKey(psProperty.ToLower) Then
            Return mhtProperties(psProperty.ToLower).NewValue
        Else
            Return Nothing
        End If
    End Function
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Returns the datastate state of the object.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>    
    ''' -----------------------------------------------------------------------------
    Public ReadOnly Property State() As DataState
        Get
            Dim ReturnValue As DataState = DataState.IsDirty

            If mbIsDeleted Then
                Return DataState.IsDeleted
            End If
            If Not Properties.ContainsKey(Key.ToLower) Then
                ReturnValue = DataState.IsNew
            End If

            Return ReturnValue
        End Get

    End Property
    Protected Function CastToString(ByVal poValue As Object) As String
        If poValue Is Nothing Then
            Return ""
        ElseIf IsDBNull(poValue) Then
            Return ""
        Else
            Return HTMLDeCode(CStr(poValue))
        End If
    End Function

    Protected Function HTMLDeCode(ByVal ps As String) As String
        If IsHTML Then
            Dim loContext As New System.Web.HttpApplication
            Return loContext.Server.HtmlDecode(ps)
        Else
            Return ps
        End If
    End Function
    Protected Function HTMLEnCode(ByVal ps As String) As String
        If IsHTML Then
            Dim loContext As New System.Web.HttpApplication
            Return loContext.Server.HtmlEncode(ps)
        Else
            Return ps
        End If
    End Function

    Protected Function CastToLong(ByVal poValue As Object) As Long
        If poValue Is Nothing Then
            Return 0
        ElseIf IsDBNull(poValue) Then
            Return 0
        Else
            Return CLng(poValue)
        End If
    End Function
    Protected Function CastToInteger(ByVal poValue As Object) As Integer
        If poValue Is Nothing Then
            Return 0
        ElseIf IsDBNull(poValue) Then
            Return 0
        Else
            Return CInt(poValue)
        End If
    End Function
    Protected Function CastToDate(ByVal poValue As Object) As Date
        If poValue Is Nothing Then
            Return NULL_DATE
        ElseIf IsDBNull(poValue) Then
            Return NULL_DATE
        Else
            Return CDate(poValue)
        End If
    End Function
    Protected Function CastToBoolean(ByVal poValue As Object) As Boolean
        If poValue Is Nothing Then
            Return False
        ElseIf IsDBNull(poValue) Then
            Return False
        Else
            Return CBool(poValue)
        End If
    End Function
    Protected Function CastToDouble(ByVal poValue As Object) As Double
        If poValue Is Nothing Then
            Return 0
        ElseIf IsDBNull(poValue) Then
            Return 0
        Else
            Return CDbl(poValue)
        End If

    End Function
    Public Overridable Sub Save()
        Dim loTran As New CTransaction()

        AddHandler loTran.AfterSave, AddressOf OnAfterSave
        AddHandler loTran.TransactionOutput, AddressOf OnTransactionOutPut
        AddHandler loTran.BeforeSave, AddressOf OnBeforeSave

        loTran.AddObject(Me)
        loTran.Save()

    End Sub
    Private Sub OnAfterSave(ByVal poObj As CObject, ByVal pdbTran As SqlTransaction, ByVal pdbConn As SqlConnection)
        If Not delAfterSave Is Nothing Then
            delAfterSave.Invoke(poObj, pdbTran, pdbConn)
        End If
    End Sub
    Private Sub OnBeforeSave(ByVal poObj As CObject, ByVal pdbTran As SqlTransaction, ByVal pdbConn As SqlConnection)
        If Not delBeforeSave Is Nothing Then
            delBeforeSave.Invoke(poObj, pdbTran, pdbConn)
        End If
    End Sub
    Private Sub OnTransactionOutPut(ByVal poObject As Object)
        If Not delTransactionOutPut Is Nothing Then
            delTransactionOutPut.Invoke(poObject)
        End If
    End Sub

    Public Property TestMode() As Boolean
        Get
            Return mbTestMode
        End Get
        Set(ByVal value As Boolean)
            mbTestMode = value
        End Set
    End Property
    Public Sub Delete()
        MarkAsDeleted()
        Dim loTran As New CTransaction

        loTran.AddObject(Me)
        AddHandler loTran.AfterSave, AddressOf OnAfterSave
        AddHandler loTran.BeforeSave, AddressOf OnBeforeSave
        loTran.Save()
    End Sub
End Class
 


